//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<expose_basic_to_python.cpp>
///	@path	~/xeres/src/python/wrap/
///	@date	2007/12/09
///	@desc	Expose basic object interface to python.

#include "python_pre.h"

#include "lib/utilities/debug.h"
#include "lib/utilities/observer.h"
#include "lib/system/sysinfo.h"
#include "lib/math/math_ext.h"
#include "lib/math/pair.h"
#include "lib/math/vector.h"
#include "lib/math/color.h"
#include "lib/math/quat.h"
#include "lib/math/matrix.h"
#include "lib/math/rect.h"
#include "lib/math/quad.h"
#include "lib/math/box.h"

#include "object/IObject.h"
#include "object/IBuffer.h"
#include "object/IVar.h"
#include "object/CVar.h"

#include "python/wrap/expose_decl_python.h"

namespace xeres {

	namespace
	{
		// Call wrap of observer iteration.
		static bool ObserveCallWrap( object call , ObserverType type , Observer * observer , const WString& label )
		{
			object retval;
			WString desc = observer ? observer->GetDesc() : _S("");
			boost::any value = observer ? observer->GetValue() : boost::any(0);
			try
			{
				retval = call( type , label , desc , value );
				if( retval == object() )
					return true;
				return extract<bool>( retval );
			}
			catch( error_already_set )
			{
				PyErr_Print();
				PyErr_Clear();
			}
			return false;
		}

		// Call wrap of invoking observation.
		static bool ObserveWrap( const WString& path , object call )
		{
			if( !PyCallable_Check( call.ptr() ) )
			{
				PyErr_SetString( PyExc_ValueError, "Object is not callable." );
				boost::python::throw_error_already_set();
			}
			return Observer::root()->VisitChildren( path , bind( ObserveCallWrap , call , _1 ,_2 , _3  ) );
		}
	}

	// expose debug class & functions
	static void expose_debug( void )
	{
		enum_< ObserverType >("ObserverType")
			.value( "readonly" , OBSERVER_READONLY )
			.value( "writable" , OBSERVER_WRITABLE )
			.value( "directory" , OBSERVER_DIR )
			.value( "end_dir" , OBSERVER_last )
		;

		// visit observer
		def( "observe" , &ObserveWrap );

		// TODO: Add observer modification function.
	}

	namespace
	{
		// Inline codes to module.
		object InlineCodeWrap( const WString& moduleName , object co )
		{
			AString m;
			wcs_to_mbs( moduleName , m );
			return PythonPlug::instance().InlineCompiled( m.c_str() , co );
		}
		// Get application directory wrap.
		WString GetAppDirWrap( void )
		{
			return get_app_dir();
		}
	}

	// expose library functions
	static void expose_lib( void )
	{
		def( "InlineCode" , &InlineCodeWrap );
		def( "GetAppDir" , &GetAppDirWrap );
	}

	namespace
	{
		//////////////////////////////////////////////////////////////////////////
		// Basic attributes.

		std::string ReprPair( Pair<float> * pair )
		{
			char buf[256];
			sprintf( buf , "<xeres.Pair object (%g,%g)>" , pair->x , pair->y );
			return buf;
		}

		std::string ReprVector( Vector<float> * vec )
		{
			char buf[256];
			sprintf( buf , "<xeres.Vector object (%g,%g,%g)>" , vec->x , vec->y , vec->z );
			return buf;
		}

		std::string ReprQuat( Quat<float> * quat )
		{
			char buf[256];
			sprintf( buf , "<xeres.Quat object (%g,%g,%g | %g)>" , quat->x , quat->y , quat->z , quat->real );
			return buf;
		}

		std::string ReprMatrix( Matrix<float> * mat )
		{
			return "<xeres.Matrix object [...]>";
		}

		std::string ReprColor( Color4 * col )
		{
			char buf[256];
			sprintf( buf , "<xeres.Color object (%g,%g,%g,%g)>" , col->r , col->g , col->b , col->a );
			return buf;
		}

		std::string ReprRegion( Rect<float> * rect )
		{
			char buf[256];
			sprintf( buf , "<xeres.Region object (pos:%g,%g - %g,%g | w:%g h:%g)>" ,
				rect->left() , rect->top() , rect->right() , rect->bottom() , rect->width() , rect->height() );
			return buf;
		}

		std::string ReprARGB( ARGB * argb )
		{
			char buf[256];
			sprintf( buf , "<xeres.ARGB object (0x%08x | %i %i %i %i)>" , argb->argb , argb->a , argb->r , argb->g , argb->b );
			return buf;
		}

		std::string ReprRGBA( RGBA * rgba )
		{
			char buf[256];
			sprintf( buf , "<xeres.RGBA object (0x%08x | %i %i %i %i)>" , rgba->rgba , rgba->r , rgba->g , rgba->b , rgba->a );
			return buf;
		}

		std::string ReprPoint( Pair<int> * pair )
		{
			char buf[256];
			sprintf( buf , "<xeres.Point object (%i,%i)>" , pair->x , pair->y );
			return buf;
		}

		std::string ReprRect( Rect<int> * rect )
		{
			char buf[256];
			sprintf( buf , "<xeres.Rect object (pos:%i,%i - %i,%i | w:%i h:%i)>" ,
				rect->left() , rect->top() , rect->right() , rect->bottom() , rect->width() , rect->height() );
			return buf;
		}

		//////////////////////////////////////////////////////////////////////////
		// Sequence conversion.

		// Convert python tuple to specific sequence type.
		template<
			typename _Type , int _Count , typename _Conversion
		> struct seq_from_python_tuple
		{
			seq_from_python_tuple( void )
			{
				boost::python::converter::registry::push_back(
					&convertible,
					&construct,
					boost::python::type_id< _Type >());
			}

			static void * convertible( PyObject* obj_ptr )
			{
				if( !PyTuple_Check(obj_ptr) || PyTuple_GET_SIZE(obj_ptr) != _Count ) return 0;
				for( int i = 0 ; i < _Count ; ++i )
				{
					PyObject * obj = PyTuple_GetItem( obj_ptr , i );
					if( !PyFloat_Check( obj ) && !PyInt_Check( obj ) )
						return 0;
				}
				return obj_ptr;
			}

			static void construct( PyObject* obj_ptr,
				boost::python::converter::rvalue_from_python_stage1_data* data )
			{
				_Conversion conversion;
				_Type * obj = (_Type*)(
					(boost::python::converter::rvalue_from_python_storage< _Type >*)data)->storage.bytes;
				conversion( obj , obj_ptr );
				data->convertible = obj;
			}
		};

		template<
			typename _Type , typename _Element , int _Count
		>struct array_from_tuple
		{
			void operator () ( _Type * obj , PyObject * tuple_ptr ) const
			{
				new (obj) _Type;
				for( int i = 0 ; i < _Count ; ++i )
				{
					PyObject * pEntry = PyTuple_GetItem( tuple_ptr , i );
					(*obj)[i] = boost::python::extract<_Element>( pEntry );
				}
			}
		};

		template<
			typename _Type
		> struct rect_from_tuple
		{
			void operator () ( Rect<_Type> * obj , PyObject * tuple_ptr ) const
			{
				new (obj) Rect<_Type>( make_rect<_Type>(
					boost::python::extract<_Type>( PyTuple_GetItem( tuple_ptr , 0 ) ),
					boost::python::extract<_Type>( PyTuple_GetItem( tuple_ptr , 1 ) ),
					boost::python::extract<_Type>( PyTuple_GetItem( tuple_ptr , 2 ) ),
					boost::python::extract<_Type>( PyTuple_GetItem( tuple_ptr , 3 ) ) ) );
			}
		};

		// Convert quaternion from a ((f,f,f),f) tuple.
		struct quat_from_python_tuple
		{
			quat_from_python_tuple( void )
			{
				boost::python::converter::registry::push_back(
					&convertible,
					&construct,
					boost::python::type_id< Quat<float> >());
			}

			static void * convertible( PyObject* obj_ptr )
			{
				if( !PyTuple_Check(obj_ptr) || PyTuple_GET_SIZE(obj_ptr) != 2 ) return 0;
				PyObject * vec = PyTuple_GetItem( obj_ptr , 0 );
				PyObject * rad = PyTuple_GetItem( obj_ptr , 1 );
				if( !PyTuple_Check(vec) || PyTuple_GET_SIZE(vec) != 3 ) return 0;
				if( !PyFloat_Check(rad) && ! PyInt_Check(rad) ) return 0;
				for( int i = 0 ; i < 3 ; ++i )
				{
					PyObject * obj = PyTuple_GetItem( vec , i );
					if( !PyFloat_Check( obj ) && !PyInt_Check( obj ) )
						return 0;
				}
				return obj_ptr;
			}

			static void construct( PyObject* obj_ptr,
				boost::python::converter::rvalue_from_python_stage1_data* data )
			{
				PyObject * vec = PyTuple_GetItem( obj_ptr , 0 );
				PyObject * rad = PyTuple_GetItem( obj_ptr , 1 );

				Quat<float> * obj = (Quat<float>*)(
					(boost::python::converter::rvalue_from_python_storage< Pair<float> >*)data)->storage.bytes;
				obj = new(obj) Quat<float>(
					boost::python::extract<float>( PyTuple_GetItem( vec , 0 ) ) ,
					boost::python::extract<float>( PyTuple_GetItem( vec , 1 ) ) ,
					boost::python::extract<float>( PyTuple_GetItem( vec , 2 ) ) ,
					boost::python::extract<float>( rad )
					);
				data->convertible = obj;
			}
		};

		struct matrix_from_tuple
		{
			void operator () ( Matrix<float> * obj , PyObject * tuple_ptr ) const
			{
				new (obj) Matrix<float>(
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 0 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 1 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 2 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 3 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 4 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 5 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 6 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 7 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 8 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 9 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 10 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 11 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 12 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 13 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 14 ) ),
					boost::python::extract<float>( PyTuple_GetItem( tuple_ptr , 15 ) ) );
			}
		};

		//////////////////////////////////////////////////////////////////////////
		// Complicate matrix calls wrap
		object MatrixRowWrap( Matrix<float> * mat , int row )
		{
			if( row < 0 || row > 3 )
			{
				PyErr_SetString(PyExc_IndexError,
					"Invalid row index for matrix.");
				boost::python::throw_error_already_set();
			}
			return boost::python::make_tuple( mat->m4x4[row][0] , mat->m4x4[row][1] , mat->m4x4[row][2] , mat->m4x4[row][3] );
		}

		object MatrixColWrap( Matrix<float> * mat , int col )
		{
			if( col < 0 || col > 3 )
			{
				PyErr_SetString(PyExc_IndexError,
					"Invalid col index for matrix.");
				boost::python::throw_error_already_set();
			}
			return boost::python::make_tuple( mat->m4x4[0][col] , mat->m4x4[1][col] , mat->m4x4[2][col] , mat->m4x4[3][col] );
		}

		float MatrixElementWrap( Matrix<float> * mat , int row , int col )
		{
			if( row < 0 || row > 3 )
			{
				PyErr_SetString(PyExc_IndexError,
					"Invalid row index for matrix.");
				boost::python::throw_error_already_set();
			}
			if( col < 0 || col > 3 )
			{
				PyErr_SetString(PyExc_IndexError,
					"Invalid col index for matrix.");
				boost::python::throw_error_already_set();
			}
			return mat->m4x4[row][col];
		}

		void MatrixRotateWrap1( Matrix<float> * mat , float rx , float ry , float rz , float rad )
		{
			mat->rotate( rx , ry , rz , rad );
		}

		void MatrixRotateWrap2( Matrix<float> * mat , const Vector<float>& a , float rad )
		{
			mat->rotate( a , rad );
		}

		//////////////////////////////////////////////////////////////////////////
		// Quad intersection wrap
		object WrapQuadIntersection( Quad * q , const Vector<float>& o , const Vector<float>& d , bool double_side )
		{
			Quad::_Intersection in;
			if( q->intersect( o , d , q->normal() , double_side , in ) )
			{
				return make_tuple( in.t , in.inter , in.u , in.v );
			}
			return object();
		}
	}

	// expose math
	static void expose_math( void )
	{
		def( "radians" , &radians<double> );
		def( "degrees" , &degrees<double> );
		def( "recip" , &recip<double> );
		def( "recip_sqrt" , &recip_sqrt<double> );
		def( "round" , &round<double> );
		def( "gamma" , &gamma<double> );
		def( "bias" , &bias<double> );
		def( "gain" , &gain<double> );
		def( "step" , &step<double> );
		def( "smoothstep" , &smoothstep<double> );
		def( "lerp" , &lerp<double> );
		def( "mix" , &mix<double> );
		def( "spline" , &spline<double> );
		def( "map_unit" , &map_unit<double> );

		to_python_converter< StringSeq , to_list< StringSeq > >();
		from_python_sequence< StringSeq , variable_capacity_policy >();

		// pair
		class_< Pair<float> >( "Pair" , init<>() )
			// ctor
			.def( init<float,float>() )
			// data
			.def_readwrite( "x" , &Pair<float>::x )
			.def_readwrite( "y" , &Pair<float>::y )
			.add_property( "theta" , &Pair<float>::theta )
			.add_property( "normalized" , &Pair<float>::normalized )
			// methods
			.def( "set" , &Pair<float>::set )
			.def( "single" , &Pair<float>::single )
			.def( "square" , &Pair<float>::square )
			.def( "length" , &Pair<float>::length )
			.def( "normalize" , &Pair<float>::normalize )
			.def( "distance" , &Pair<float>::distance<float> )
			.def( "dot" , &Pair<float>::dot<float> )
			.def( "cross" , &Pair<float>::cross<float,float> )
			// operator
			.def( - self )
			.def( self + float() )
			.def( self + Pair<float>() )
			.def( self - float() )
			.def( self - Pair<float>() )
			.def( self * float() )
			.def( self * Pair<float>() )
			.def( self / float() )
			.def( self / Pair<float>() )
			.def( self += float() )
			.def( self += Pair<float>() )
			.def( self -= float() )
			.def( self -= Pair<float>() )
			.def( self *= float() )
			.def( self *= Pair<float>() )
			.def( self /= float() )
			.def( self /= Pair<float>() )
			.def( self == Pair<float>() )
			.def( self != Pair<float>() )
			.def( "__repr__" , &ReprPair )
		;
		seq_from_python_tuple< Pair<float> , 2 , array_from_tuple< Pair<float> , float , 2 > >();
		to_python_converter< std::vector< Pair<float> > , to_list< std::vector< Pair<float> > > >();

		// vector
		class_< Vector<float> >( "Vector" , init<>() )
			// ctor
			.def( init<float,float,float>() )
			// data
			.def_readwrite( "x" , &Vector<float>::x )
			.def_readwrite( "y" , &Vector<float>::y )
			.def_readwrite( "z" , &Vector<float>::z )
			.add_property( "theta" , &Vector<float>::theta )
			.add_property( "phi" , &Vector<float>::phi )
			.add_property( "normalized" , &Vector<float>::normalized )
			// method
			.def( "set" , &Vector<float>::set )
			.def( "single" , &Vector<float>::single )
			.def( "square" , &Vector<float>::square )
			.def( "length" , &Vector<float>::length )
			.def( "normalize" , &Vector<float>::normalize )
			.def( "distance" , &Vector<float>::distance<float> )
			.def( "dot" , &Vector<float>::dot<float> )
			.def( "cross" , &Vector<float>::cross<float,float> )
			// operator
			.def( - self )
			.def( self + float() )
			.def( self + Vector<float>() )
			.def( self - float() )
			.def( self - Vector<float>() )
			.def( self * float() )
			.def( self * Vector<float>() )
			.def( self / float() )
			.def( self / Vector<float>() )
			.def( self += float() )
			.def( self += Vector<float>() )
			.def( self -= float() )
			.def( self -= Vector<float>() )
			.def( self *= float() )
			.def( self *= Vector<float>() )
			.def( self /= float() )
			.def( self /= Vector<float>() )
			.def( self == Vector<float>() )
			.def( self != Vector<float>() )
			.def( "__repr__" , &ReprVector )
		;
		seq_from_python_tuple< Vector<float> , 3 , array_from_tuple< Vector<float> , float , 3 > >();

		// quaternion
		class_< Quat<float> >( "Quat" , init<>() )
			// ctor
			.def( init<float,float,float,float>() )
			.def( init<Vector<float> ,float>() )
			// data
			.add_property( "angle" , &Quat<float>::angle , &Quat<float>::set_angle )
			.add_property( "axis" , &Quat<float>::axis , &Quat<float>::set_axis )
			.add_property( "matrix" , &Quat<float>::to_matrix )
			.add_property( "invert" , &Quat<float>::invert )
			.add_static_property( "identity" , make_function( &Quat<float>::_identity , RET_COPYREF ) )
			// method
			.def( "square" , &Quat<float>::square )
			.def( "length" , &Quat<float>::length )
			.def( "normalize" , &Quat<float>::normalize )
			.def( "normalized" , &Quat<float>::normalized )
			.def( "dot" , &Quat<float>::dot )
			.def( "inverse" , &Quat<float>::inverse )
			.def( "log" , &Quat<float>::log )
			.def( "exp" , &Quat<float>::exp )
			.def( "set_rotation" , &Quat<float>::set_rotation )
			// static
			.def( "angle4d" , &Quat<float>::angle4D )
			.staticmethod( "angle4d" )
			.def( "slerp" , &Quat<float>::slerp )
			.staticmethod( "slerp" )
			.def( "spline" , &Quat<float>::spline )
			.staticmethod( "spline" )
			.def( "squad" , &Quat<float>::squad )
			.staticmethod( "squad" )
			// operator
			.def( - self )
			.def( self += Quat<float>() )
			.def( self -= Quat<float>() )
			.def( self *= Quat<float>() )
			.def( self *= float() )
			.def( self /= float() )
			.def( self /= Quat<float>() )
			.def( self + Quat<float>() )
			.def( self + float() )
			.def( self - Quat<float>() )
			.def( self - float() )
			.def( self * Quat<float>() )
			.def( self * float() )
			.def( self / Quat<float>() )
			.def( self / float() )
			.def( "__repr__" , &ReprQuat )
		;
		quat_from_python_tuple();

		// matrix
		class_< Matrix<float> >( "Matrix" , init<>() )
			// ctor
			// data
			.add_property( "transposed" , &Matrix<float>::transposed )
			.add_property( "invert" , &Matrix<float>::invert )
			.add_property( "det" , &Matrix<float>::det )
			.add_property( "origin" , &Matrix<float>::origin )
			.add_property( "is_identity" , &Matrix<float>::is_identity )
			.add_static_property( "identity" , make_function( &Matrix<float>::_identity , RET_COPYREF ) )
			// method
			.def( "transpose" , &Matrix<float>::transpose )
			.def( "inverse" , &Matrix<float>::inverse )
			.def( "rotate" , &MatrixRotateWrap1 )
			.def( "rotate" , &MatrixRotateWrap2 )
			.def( "row" , &MatrixRowWrap )
			.def( "col" , &MatrixColWrap )
			.def( "element" , &MatrixElementWrap )
			.def( "multiply_to" , &Matrix<float>::multiply_to )
			.def( "multiply_from" , &Matrix<float>::multiply_from )
			// operator
			.def( self == Matrix<float>() )
			.def( self != Matrix<float>() )
			.def( "__repr__" , &ReprMatrix )
		;
		seq_from_python_tuple< Matrix<float> , 16 , matrix_from_tuple >();

		// color
		class_< Color4 >( "Color" , init<>() )
			// ctor
			.def( init<float,float,float,float>() )
			// data
			.def_readwrite( "r" , &Color4::r )
			.def_readwrite( "g" , &Color4::g )
			.def_readwrite( "b" , &Color4::b )
			// method
			.def( "single" , &Color4::single )
			.def( "clamp" , &Color4::clamp )
			// static
			.def( "min" , &Color4::minc )
			.staticmethod( "min" )
			.def( "max" , &Color4::maxc )
			.staticmethod( "max" )
			.def( "is_equal" , &Color4::is_equalc )
			.staticmethod( "is_equal" )
			// operator
			.def( "__repr__" , &ReprColor )
		;
		seq_from_python_tuple< Color4 , 4 , array_from_tuple< Color4 , float , 4 > >();

		// region
		class_< Rect<float> >( "Region" , init<float,float,float,float>() )
			// ctor
			// data
			.add_property( "width" , &Rect<float>::width )
			.add_property( "height" , &Rect<float>::height )
			.add_property( "left" , &Rect<float>::left )
			.add_property( "top" , &Rect<float>::top )
			.add_property( "right" , &Rect<float>::right )
			.add_property( "bottom" , &Rect<float>::bottom )
			.add_property( "xmin" , &Rect<float>::xmin )
			.add_property( "ymin" , &Rect<float>::ymin )
			.add_property( "xmax" , &Rect<float>::xmax )
			.add_property( "ymax" , &Rect<float>::ymax )
			// method
			.def( "set" , &Rect<float>::set<float,float,float,float> )
			// operator
			.def( "__repr__" , &ReprRegion )
		;
		seq_from_python_tuple< Rect<float> , 4 , rect_from_tuple<float> >();

		// pair as size
		class_< Pair<int> >( "Point" , init<>() )
			// ctor
			.def( init<int,int>() )
			// data
			.def_readwrite( "x" , &Pair<int>::x )
			.def_readwrite( "y" , &Pair<int>::y )
			// methods
			.def( "set" , &Pair<int>::set )
			.def( "single" , &Pair<int>::single )
			.def( self == Pair<int>() )
			.def( self != Pair<int>() )
			// operator
			.def( "__repr__" , &ReprPoint )
		;
		seq_from_python_tuple< Pair<int> , 2 , array_from_tuple< Pair<int> , int , 2 > >();

		// rect
		class_< Rect<int> >( "Rect" , init<int,int,int,int>() )
			// ctor
			.def( init<int,int,const Pair<int>&>() )
			// property
			.add_property( "is_empty" , &Rect<int>::is_empty )
			.add_property( "width" , &Rect<int>::width )
			.add_property( "height" , &Rect<int>::height )
			.add_property( "left" , &Rect<int>::left )
			.add_property( "top" , &Rect<int>::top )
			.add_property( "right" , &Rect<int>::right )
			.add_property( "bottom" , &Rect<int>::bottom )
			.add_property( "xmin" , &Rect<int>::xmin )
			.add_property( "ymin" , &Rect<int>::ymin )
			.add_property( "xmax" , &Rect<int>::xmax )
			.add_property( "ymax" , &Rect<int>::ymax )
			// method
			.def( "set" , &Rect<int>::set<int,int,int,int> )
			.def( "empty" , &Rect<int>::empty )
			.def( "is_inside" , &Rect<int>::is_inside<int> )
			.def( "is_overlap" , &Rect<int>::is_overlap<int> )
			// operator
			.def( "__repr__" , &ReprRect )
		;
		seq_from_python_tuple< Rect<int> , 4 , rect_from_tuple<int> >();

		def( "rect" , make_rect<int> );

		// color formats
		class_< ARGB >( "ARGB" , init<int,int,int,int>() )
			// ctor
			.def( init<uint>() )
			.def( init<const Color4&>() )
			// data
			.def_readwrite( "r" , &ARGB::r )
			.def_readwrite( "g" , &ARGB::g )
			.def_readwrite( "b" , &ARGB::b )
			.def_readwrite( "a" , &ARGB::a )
			// operator
			.def( "__repr__" , &ReprARGB )
		;
		boost::python::implicitly_convertible<uint,ARGB>();

		class_< RGBA >( "RGBA" , init<int,int,int,int>() )
			// ctor
			.def( init<uint>() )
			.def( init<const Color4&>() )
			// data
			.def_readwrite( "r" , &RGBA::r )
			.def_readwrite( "g" , &RGBA::g )
			.def_readwrite( "b" , &RGBA::b )
			.def_readwrite( "a" , &RGBA::a )
			// operator
			.def( "__repr__" , &ReprRGBA )
		;

		class_< Quad >( "Quad" , init<>() )
			// ctor
			.def( init<const Vector<float>&,const Vector<float>&,const Vector<float>&,const Vector<float>&>() )
			.def( init<const Rect<float>&,float>() )
			// property
			.add_property( "v00" , make_function( &Quad::v00 , RET_COPYREF ) )
			.add_property( "v01" , make_function( &Quad::v01 , RET_COPYREF ) )
			.add_property( "v10" , make_function( &Quad::v10 , RET_COPYREF ) )
			.add_property( "v11" , make_function( &Quad::v11 , RET_COPYREF ) )
			//
			.def( "intersect" , &WrapQuadIntersection )
		;

		class_< Box<float> >( "Box" , init<>() )
			// ctor
			.def( init<const Vector<float>&,const Vector<float>&>() )
			.def( init<const Box<float>&>() )
			// property
			.add_property( "is_empty" , &Box<float>::is_empty )
			.add_property( "bmin" , make_function( &Box<float>::get_min , RET_COPYREF ) )
			.add_property( "bmax" , make_function( &Box<float>::get_max , RET_COPYREF ) )
			// method
			//.def( "set" , &Box<float>::set<float> )
			.def( "empty" , &Box<float>::empty )
			.def( "is_inside" , &Box<float>::is_inside<float> )
			.def( "is_overlap" , &Box<float>::is_overlap<float> )
			.def( "center" , &Box<float>::center )
			.def( "distance" , &Box<float>::distance<float> )
		;
	}

	namespace
	{
		std::string IObjectRepr( IObject * comp )
		{
			char buf[256];
			sprintf( buf , "<xeres.%S object (addr:%0x)>" , comp->GetClassName().c_str() , comp );
			return buf;
		}

		// IsA method wrap.
		bool IObjectIsAWrap( IObject * obj , const AString& className )
		{
			WString buf;
			mbs_to_wcs( className.c_str() , buf );
			return obj->IsA( buf );
		}

		// Comparison
		bool IObjectComparison( IObject * left , IObject * right )
		{
			return left == right;
		}
		bool IObjectComparisonNeg( IObject * left , IObject * right )
		{
			return left != right;
		}

		// convert to generic IObject.
		Ref<IObject> ConvertGeneric( IObject * obj )
		{
			return obj;
		}

		// actual object
		PyObject * ActualObject( IObject * obj )
		{
			return get_python_converters( obj->GetClassID() ).to_python( &Ref<IObject>(obj) );
		}

		//////////////////////////////////////////////////////////////////////////
		// CVar conversion

		int CVar2Int( CVar * var )
		{
			int val = INT_MAX;
			var->GetInt( val );
			return val;
		}

		float CVar2Float( CVar * var )
		{
			float val = ArithmeticOp<float>::nan();
			var->GetFloat( val );
			return val;
		}

		WString CVar2String( CVar * var )
		{
			WString val;
			var->GetString( val );
			return val;
		}

		Ref<IObject> CreateObjectWrap( const WString& name )
		{
			return Ref<IObject>( ObjectFactory::CreateObject( name ) );
		}
	}

	// expose IObject
	static void expose_object( void )
	{
		class_< IObject , boost::noncopyable >( "IObject" , no_init )
			// Get class name
			.def( "GetClassName" , &IObject::GetClassName , return_value_policy<copy_const_reference>() )
			// Class identification
			.def( "IsA" , &IObjectIsAWrap )
			//
			.def( "__eq__" , &IObjectComparison )
			.def( "__ne__" , &IObjectComparisonNeg )
			.def( "__repr__" , &IObjectRepr )
		;
		register_ptr_to_python< Ref<IObject> >();
		register_object_to_python<IObject>();

		class_< IBuffer , Ref< IBuffer > , bases< IObject > >( "IBuffer" , no_init )
			// Object property.
			.add_property( "size" , &IBuffer::GetSize )
		;
		register_object_to_python<IBuffer>();

		def( "CreateObject" , &CreateObjectWrap );

		def( "Generic" , &ConvertGeneric );
		def( "Actual" , &ActualObject );
	}

	// expose IVar
	static void expose_var( void )
	{
			class_< IVar , bases< IObject > , boost::noncopyable >( "IVar" , no_init )
 			// Get var type name
			.def( "GetVarTypeName" , &IVar::GetVarTypeName , return_value_policy<copy_const_reference>() )
			// Set method
 			.def( "SetBool" , &IVar::SetBool )
			.def( "SetInt" , &IVar::SetInt )
			.def( "SetPair" , &IVar::SetPair )
			.def( "SetVector" , &IVar::SetVector )
			.def( "SetQuat" , &IVar::SetQuat )
			.def( "SetColor" , &IVar::SetColor )
			.def( "SetMatrix" , &IVar::SetMatrix )
			.def( "SetString" , &IVar::SetString )
			// Attributes
 			.add_property( "bool" , &IVar::AttrBool )
 			.add_property( "int" , &IVar::AttrInt )
			.add_property( "float" , &IVar::AttrFloat )
			.add_property( "pair" , &IVar::AttrPair )
			.add_property( "vector" , &IVar::AttrVector )
			.add_property( "matrix" , &IVar::AttrMatrix )
 			.add_property( "string" , &IVar::AttrString )
 		;
		register_ptr_to_python< Ref<IVar> >();
		register_object_to_python<IVar>();

		class_< CVar , Ref<CVar> , bases< IVar > >( "CVar" , init<>() )
			// ctor
			.def( init<bool>() )
			.def( init<int>() )
			.def( init<float>() )
			.def( init<const Pair<float>&>() )
			.def( init<const Vector<float>&>() )
			.def( init<const Matrix<float>&>() )
			.def( init<const Quat<float>&>() )
			.def( init<const WString&>() )
			.def( init< Ref<IObject> >() )
			// conversion
			.def( "__int__" , &CVar2Int )
			.def( "__float__" , &CVar2Float )
			.def( "__str__" , &CVar2String )
		;
		register_object_to_python<CVar>();
	}

	namespace
	{
		std::vector<ClassID> registered_class;

		static const char * register_class_key = "xeres.IObject.python.registry";

		struct _IObjectPythonSlot
		{
			const registration * reg;
		};

		// clear all registration
		static void clear_registration( void )
		{
			for( size_t i = 0 , total = registered_class.size() ; i < total ; ++i )
			{
				ClassID id = registered_class[i];
				void * value;
				XS_VERIFY( GetClassSlot( id , register_class_key , value ) );
				delete ((_IObjectPythonSlot *)value);
				DelClassSlot( id , register_class_key );
			}
			registered_class.clear();
		}
	}

	void register_object_to_python( ClassID id , const registration * reg )
	{
		_IObjectPythonSlot * slot = new _IObjectPythonSlot;
		slot->reg = reg;

		if( !RegisterClassSlot( id , register_class_key , slot ) )
		{
			XS_VERIFY( SetClassSlot( id , register_class_key , slot ) );
		}
		registered_class.push_back( id );
	}

	const registration& get_python_converters( ClassID id )
	{
		void * value;
		XS_VERIFY( GetInheritClassSlot( id , register_class_key , value ) );
		return *((_IObjectPythonSlot *)value)->reg;
	}

	namespace
	{
#define __declspec(X)

		BOOST_PYTHON_MODULE( xeres_basic )
		{
			expose_debug();
			expose_lib();
			expose_math();
			expose_object();
			expose_var();
		}

#undef __declspec
	}

	// expose basic functions
	void expose_basic_to_python( void )
	{
		XS_ASSERT( PythonPlug::instance().IsInitialized() );
		boost::python::from_python_any();

#ifndef _PYXERES
		PythonPlug::instance().RegisterModule( "xeres" , init_module_xeres_basic );
#else
		init_module_xeres_basic();
#endif

		PythonPlug::instance().RegisterCleanup( clear_registration );
	}

} // namespace xeres
